BUUCTF Reverse WriteUp easyre 直接拖进IDA分析,拖进PEID发现不是有效的PE文件
找到main函数,送分题
1 2 3 4 5 6 7 8 9 10 11 12 13 int  __cdecl main (int  argc, const  char  **argv, const  char  **envp)  {  int  b;    int  a;    _main();   scanf ("%d%d" , &a, &b);   if  ( a == b )     printf ("flag{this_Is_a_EaSyRe}" );   else      printf ("sorry,you can't get flag" );   return  0 ; } 
 
flag{this_Is_a_EaSyRe}
reverse1 直接拖进IDA分析,是个64位exe可执行文件
shift+F12大法找到wrong flag,然后查看引用找到main函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 __int64 sub_1400118C0 ()   {  char  *v0;    signed  __int64 i;    size_t  v2;    size_t  v3;    char  v5;    int  j;    char  Str1;    unsigned  __int64 v8;    v0 = &v5;   for  ( i = 82 i64; i; --i )   {     *(_DWORD *)v0 = -858993460 ;     v0 += 4 ;   }   for  ( j = 0 ; ; ++j )   {     v8 = j;     v2 = j_strlen(Str2);     if  ( v8 > v2 )       break ;     if  ( Str2[j] == 111  )       Str2[j] = 48 ;   }   sub_1400111D1("input the flag:" );   sub_14001128F("%20s" , &Str1);   v3 = j_strlen(Str2);   if  ( !strncmp (&Str1, Str2, v3) )     sub_1400111D1("this is the right flag!\n" );   else      sub_1400111D1("wrong flag\n" );   sub_14001113B(&v5, &unk_140019D00);   return  0 i64; } 
 
这个Str2就是我们要找的flag了,虽然可以下断点直接跳出来,但是觉得太麻烦,直接逆
上面的for就是把Str2里面的o换成0,跟一下发现是{hello_world}
提交flagflag{hell0_w0rld}
reverse2 惯例拖进IDA,发现这次是ELF的x86_64,直接找到main函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 int  __cdecl main (int  argc, const  char  **argv, const  char  **envp)  {  int  result;    int  stat_loc;    int  i;    __pid_t  pid;    char  s2;    unsigned  __int64 v8;    v8 = __readfsqword(0x28 u);   pid = fork();   if  ( pid )   {     argv = (const  char  **)&stat_loc;     waitpid(pid, &stat_loc, 0 );   }   else    {     for  ( i = 0 ; i <= strlen (&flag); ++i )     {       if  ( *(&flag + i) == 105  || *(&flag + i) == 114  )         *(&flag + i) = 49 ;     }   }   printf ("input the flag:" , argv);   __isoc99_scanf("%20s" , &s2);   if  ( !strcmp (&flag, &s2) )     result = puts ("this is the right flag!" );   else      result = puts ("wrong flag!" );   return  result; } 
 
发现有个fork操作,多进程,不管这么多先直接看上面主线程的for
1 2 3 4 5 for  ( i = 0 ; i <= strlen (flag); ++i ){   if  ( flag[i] == 'i'  || flag[i] == 'r'  )     flag[i] = '1' ; } 
 
把flag里面的i/r换成1
再跟一下flag是{hacking_for_fun} 得到变换后的flagflag{hack1ng_fo1_fun}
提交得分,居然没有在多进程里面设坑……
新年快乐 拖进PEID查看发现加了个UPX的壳,随便找个脱壳机给脱了,发现我的脱壳机还脱不下来,upx官方脱壳机,直接在官方下载一个最新的UPX,脱下来之后, 用PEID再看发现是yoda's Protector什么的,直接拖进IDA看看,找到main 函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 int  __cdecl main (int  argc, const  char  **argv, const  char  **envp)  {  int  result;    char  v4;    __int16 v5;    __int16 v6;    __main();   strcpy (&v4, "HappyNewYear!" );   v5 = 0 ;   memset (&v6, 0 , 0x1E u);   printf ("please input the true flag:" );   scanf ("%s" , &v5);   if  ( !strncmp ((const  char  *)&v5, &v4, strlen (&v4)) )     result = puts ("this is true flag!" );   else      result = puts ("wrong!" );   return  result; } 
 
直接拿到flag HappyNewYear!
内涵的软件 好家伙一来就是一个EXE,拖进IDA发现是个X86的exe,旁边函数列表一大堆,还是老规矩找字符串
手动运行一下程序,挺有趣的
1 2 3 4 5 6 7 8 9 10 11 12 13 PS .\70125468-0786-4705-bd91-87037f8f3e16.exe 距离出现答案还有5秒,请耐心等待! 距离出现答案还有4秒,请耐心等待! 距离出现答案还有3秒,请耐心等待! 距离出现答案还有2秒,请耐心等待! 距离出现答案还有1秒,请耐心等待! 距离出现答案还有0秒,请耐心等待! 这里本来应该是答案的,但是粗心的程序员忘记把变量写进来了,你要不逆向试试看:(Y/N) Y OD吾爱破解或者IDA这些逆向软件都挺好的! 
 
于是在main里面找到字符串DBAPP{49d3c93df25caad81232130f3d2ebfad},交上去不对
然后看了下提示,把DBAPP ,换成flag,出了,艹
guessgame 拖进IDA,先跑一下,然后发现main函数逻辑非常明确
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 int  __cdecl main (int  argc, const  char  **argv, const  char  **envp)  {  unsigned  int  v3;    int  v4;    _main();   v4 = 0 ;   v3 = time(0 i64);   srand(v3);   while  ( 1  )   {     menu();     printf (QingXuanZe);     scanf ("%d" , &v4);     if  ( v4 == 1  )     {       game();     }     else  if  ( v4 == 2  )     {       puts ("想啥呢弟弟" );     }     else  if  ( v4 )     {       puts (XuanZeCuoWu);     }     else      {       puts ("退出游戏" );     }   } } 
 
优化一下变量名,还是比较清晰的,进入game里面看看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 int  game ()  {  int  input;    int  randNum;    input = 0 ;   randNum = rand() % 100  + 1 ;   while  ( 1  )   {     while  ( 1  )     {       printf (QingShuRuShuZi);       scanf ("%d" , &input);       if  ( input <= randNum )         break ;       puts (DaLe);     }     if  ( input >= randNum )       break ;     puts (XiaoLe);   }   return  puts (aFlaga); } 
 
本质上就是一个猜数游戏,猜对了也没奖励,于是打开字符串窗口,第一个就是flag,BJD{S1mple_ReV3r5e_W1th_0D_0r_IDA},提交成功
逆了一下,原来就是把这个字符串,藏在menu的一个变量里面,估计是用的内联汇编之类的,伪代码是看不出来的,但是看汇编一下子就出来了
helloworld 下载下来发现是一个安卓apk文件,啊这,俺从来没逆向过安卓文件啊
网上找了一堆教程,发现,首先用dex2jar把apk里面的dex给反编译出jar来,然后用jar-decompiler一瞬出flag
MainActivity.class源码在这
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package  com.example.helloword;import  android.os.Bundle;import  android.support.v7.app.ActionBarActivity;import  android.view.Menu;import  android.view.MenuItem;public  class  MainActivity  extends  ActionBarActivity   {  protected  void  onCreate (Bundle paramBundle)   {     super .onCreate(paramBundle);     setContentView(2130903064 );     "flag{7631a988259a00816deda84afb29430a}" .compareTo("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" );   }      public  boolean  onCreateOptionsMenu (Menu paramMenu)   {     getMenuInflater().inflate(2131492864 , paramMenu);     return  true ;   }      public  boolean  onOptionsItemSelected (MenuItem paramMenuItem)   {     return  (paramMenuItem.getItemId() == 2131034172 ) ? true  : super .onOptionsItemSelected(paramMenuItem);   } } 
 
一瞬拿到flag
xor 下载下来二话不说直接拖进IDA,发现还是个mac平台的软件,不过也能分析出main函数的源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 int  __cdecl main (int  argc, const  char  **argv, const  char  **envp)  {  char  *v3;    int  result;    signed  int  i;    char  flag[264 ];    __int64 v7;    memset (flag, 0 , 0x100 uLL);   v3 = (char  *)256 ;   printf ("Input your flag:\n" , 0L L);   get_line(flag, 256L L);   if  ( strlen (flag) != 33  )     goto  failed;   for  ( i = 1 ; i < 33 ; ++i )     flag[i] ^= flag[i - 1 ];   v3 = global;   if  ( !strncmp (flag, global, 0x21 uLL) )     printf ("Success" , v3);   else  failed:     printf ("Failed" , v3);   result = __stack_chk_guard;   if  ( __stack_chk_guard == v7 )     result = 0 ;   return  result; } 
 
输入的flag每一位都和前一位进行xor,然后和内置的数据进行比较
然后就是写脚本出结果了
1 2 3 4 5 6 7 8 9 10 data = [   0x66 , 0x0A , 0x6B , 0x0C , 0x77 , 0x26 , 0x4F , 0x2E , 0x40 , 0x11 ,    0x78 , 0x0D , 0x5A , 0x3B , 0x55 , 0x11 , 0x70 , 0x19 , 0x46 , 0x1F ,    0x76 , 0x22 , 0x4D , 0x23 , 0x44 , 0x0E , 0x67 , 0x06 , 0x68 , 0x0F ,    0x47 , 0x32 , 0x4F , 0x00  ] for  i in  range(33 , 0 , -1 ):  data[i] ^= data[i-1 ] print('' .join([chr(x) for  x in  data])) 
 
得到结果flag{QianQiuWanDai_YiTongJiangHu}
reverse3 拖进IDA,直接找到main函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 __int64 main_0 ()   {  int  flagLength;    const  char  *v1;    size_t  v2;    int  v3;    __int64 v4;    signed  int  j;    signed  int  i;    signed  int  v8;    char  Dest[108 ];    char  flag;    char  v11;    for  ( i = 0 ; i < 100 ; ++i )   {     if  ( (unsigned  int )i >= 0x64  )       j____report_rangecheckfailure();     Dest[i] = 0 ;   }   print("please enter the flag:" );   scanf ("%20s" , &flag);   flagLength = j_strlen(&flag);   v1 = (const  char  *)sub_4110BE((int )&flag, flagLength, (int )&v11);   strncpy (Dest, v1, 40u );   v8 = j_strlen(Dest);   for  ( j = 0 ; j < v8; ++j )     Dest[j] += j;   v2 = j_strlen(Dest);   if  ( !strncmp (Dest, Str2, v2) )     print("rigth flag!\n" );   else      print("wrong flag!\n" );   HIDWORD(v4) = v3;   LODWORD(v4) = 0 ;   return  v4; } 
 
发现这次没有这么简单了,看了一下逻辑,大概是把输入的flag经过一个变换,然后再来一个每一位都加上当前的index这样的操作,最后和目的作比较
看一下这里面的变换函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 void  *__cdecl sub_411AB0 (char  *flag, unsigned  int  flagLength, int  *a3)  {  int  v4;    int  v5;    int  v6;    int  v7;    signed  int  i;    unsigned  int  v9;    int  v10;    signed  int  v11;    void  *Dst;    char  *v13;    if  ( !flag || !flagLength )     return  0 ;   v9 = flagLength / 3 ;   if  ( (flagLength / 3 ) % 3  )     ++v9;   v10 = 4  * v9;   *a3 = v10;   Dst = malloc (v10 + 1 );   if  ( !Dst )     return  0 ;   j_memset(Dst, 0 , v10 + 1 );   v13 = flag;   v11 = flagLength;   v7 = 0 ;   while  ( v11 > 0  )   {     byte_41A144[2 ] = 0 ;     byte_41A144[1 ] = 0 ;     byte_41A144[0 ] = 0 ;     for  ( i = 0 ; i < 3  && v11 >= 1 ; ++i )     {       byte_41A144[i] = *v13;       --v11;       ++v13;     }     if  ( !i )       break ;     switch  ( i )     {       case  1 :         *(Dst + v7) = aAbcdefghijklmn[byte_41A144[0 ] >> 2 ];         v4 = v7 + 1 ;         *(Dst + v4++) = aAbcdefghijklmn[((byte_41A144[1 ] & 0xF0 ) >> 4 ) | 16  * (byte_41A144[0 ] & 3 )];         *(Dst + v4++) = aAbcdefghijklmn[64 ];         *(Dst + v4) = aAbcdefghijklmn[64 ];         v7 = v4 + 1 ;         break ;       case  2 :         *(Dst + v7) = aAbcdefghijklmn[byte_41A144[0 ] >> 2 ];         v5 = v7 + 1 ;         *(Dst + v5++) = aAbcdefghijklmn[((byte_41A144[1 ] & 0xF0 ) >> 4 ) | 16  * (byte_41A144[0 ] & 3 )];         *(Dst + v5++) = aAbcdefghijklmn[((byte_41A144[2 ] & 0xC0 ) >> 6 ) | 4  * (byte_41A144[1 ] & 0xF )];         *(Dst + v5) = aAbcdefghijklmn[64 ];         v7 = v5 + 1 ;         break ;       case  3 :         *(Dst + v7) = aAbcdefghijklmn[byte_41A144[0 ] >> 2 ];         v6 = v7 + 1 ;         *(Dst + v6++) = aAbcdefghijklmn[((byte_41A144[1 ] & 0xF0 ) >> 4 ) | 16  * (byte_41A144[0 ] & 3 )];         *(Dst + v6++) = aAbcdefghijklmn[((byte_41A144[2 ] & 0xC0 ) >> 6 ) | 4  * (byte_41A144[1 ] & 0xF )];         *(Dst + v6) = aAbcdefghijklmn[byte_41A144[2 ] & 0x3F ];         v7 = v6 + 1 ;         break ;     }   }   *(Dst + v7) = 0 ;   return  Dst; } 
 
也有字母表,看上去真的很像base64,而且密码表也是base64的,就先猜是,然后写脚本
1 2 3 4 5 6 import  base64s1 = 'e3nifIH9b_C@n@dH'  s1 = list(s1) for  i in  range(len(s1)):  s1[i] = chr(ord(s1[i]) - i) print(base64.b64decode('' .join(s1))) 
 
然后就是得到flag{i_l0ve_you},果然是这个base64
不一样的flag 是个x86下windows程序,看样子像是一个迷宫题,main函数也很直接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 int  __cdecl main (int  argc, const  char  **argv, const  char  **envp)  {  char  v3;    int  x;    int  y;    signed  int  input;    int  i;    int  map ;    __main();   x = 0 ;   y = 0 ;   qmemcpy(&v3, _data_start__, 0x19 u);   while  ( 1  )   {     puts ("you can choose one action to execute" );     puts ("1 up" );     puts ("2 down" );     puts ("3 left" );     printf ("4 right\n:" );     scanf ("%d" , &input);     if  ( input == 2  )     {       ++x;     }     else  if  ( input > 2  )     {       if  ( input == 3  )       {         --y;       }       else        {         if  ( input != 4  ) LABEL_13:           exit (1 );         ++y;       }     }     else      {       if  ( input != 1  )         goto  LABEL_13;       --x;     }     for  ( i = 0 ; i <= 1 ; ++i )     {       if  ( *(&x + i) < 0  || *(&x + i) > 4  )         exit (1 );     }     if  ( *(&map  + 5  * x + y - 41 ) == '1'  )       exit (1 );     if  ( *(&map  + 5  * x + y - 41 ) == '#'  )     {       puts ("\nok, the order you enter is the flag!" );       exit (0 );     }   } } 
 
然后看汇编发现push了一串字符,应该就是地图了
*11110100001010000101111#然后是五个一行
1 2 3 4 5 *1111 01000 01010 00010 1111#` 
 
没病走两步,得到flag222441144222
SimpleRev x64的一个elf文件,拖进IDA,WSL下面直接跑不了,linux下也跑不了直接提示段错误,淦,main函数就是一个菜单,重点在decry()函数里面,跟进去
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 unsigned  __int64 Decry ()  {  char  v1;    int  v2;    int  v3;    int  i;    int  v5;    char  src[8 ];    __int64 v7;    int  v8;    __int64 v9;    __int64 v10;    int  v11;    unsigned  __int64 v12;    v12 = __readfsqword(0x28 u);   *(_QWORD *)src = 'SLCDN';   v7 = 0L L;   v8 = 0 ;   v9 = 'wodah';   v10 = 0L L;   v11 = 0 ;   text = (char  *)join(key3, &v9);   strcpy (key, key1);   strcat (key, src);   v2 = 0 ;   v3 = 0 ;   getchar();   v5 = strlen (key);   for  ( i = 0 ; i < v5; ++i )   {     if  ( key[v3 % v5] > '@'  && key[v3 % v5] <= 90  )       key[i] = key[v3 % v5] + ' ' ;                   ++v3;   }   printf ("Please input your flag:" , src);   while  ( 1  )   {     v1 = getchar();     if  ( v1 == 10  )       break ;     if  ( v1 == 32  )     {       ++v2;     }     else      {       if  ( v1 <= 96  || v1 > 122  )       {         if  ( v1 > 64  && v1 <= 90  )           str2[v2] = (v1 - 39  - key[v3++ % v5] + 97 ) % 26  + 97 ;       }       else        {         str2[v2] = (v1 - 39  - key[v3++ % v5] + 97 ) % 26  + 97 ;       }       if  ( !(v3 % v5) )         putchar (32 );       ++v2;     }   }   if  ( !strcmp (text, str2) )     puts ("Congratulation!\n" );   else      puts ("Try again!\n" );   return  __readfsqword(0x28 u) ^ v12; } 
 
进去之后有几个阴间计算,跟一下
text = killshadow  key = adsfkndcls
大概就是输入的字符和这个key进行运算之后要等于text,注意这个式子
str2[idx] = (inputChar - '\'' - key[cnt++ % kenLength] + 'a') % 26 + 'a'
这个取模让人有点难受,但是想到了取模的一个运算法则 $$ (a + b) % c=(a % c + b % c)%c $$ 又因为key里面全部都是小写字符,不可能是超过26的,而inputChar - ‘\‘的值大概在25-100之间
写个脚本穷举一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 text = list('killshadow' ) text = [ord(x) for  x in  text] key = list('adsfkndcls' ) key = [ord(x) for  x in  key] flag = [0 ] * len(text) for  i in  range(len(text)):    flag[i] = text[i] - ord('a' )     flag[i] += 26  * 2      flag[i] += key[i] - ord('a' )     flag[i] += ord('\'' ) print('' .join([chr(x) for  x in  flag])) 
 
KL^Q]UDFZi和efxkwo^t 什么阴间flag,交上去完全不对
得,看一下网上的wp,直接爆破,因为这个是按位加密的,爆破脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 def  change (x:int, index:int ):    char = (x - ord('\'' ) - (key[index] - ord('a' ))) % 26  + ord('a' )     return  char text = list('killshadow' ) text = [ord(x) for  x in  text] key = list('adsfkndcls' ) key = [ord(x) for  x in  key] flag = [0 ] * len(text) charset = list(range(ord('A' ), ord('Z' )+1 )) for  cnt in  range(len(text)):    for  i in  charset:         res = change(i, cnt)         if  res == text[cnt]:             flag[cnt] = i print('' .join([chr(x) for  x in  flag])) 
 
出了多解,一个是大写的KLDQCUDFZO,一个是小写的efxkwoxzti,按理来说中间随便混杂都满足条件,垃圾题实锤了
刮开有奖 IDA分析是个win32下的窗口化程序,然而俺只能看见一个刮开有奖,其余啥也看不见,不管,进入diagFunc 查看对话框逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 BOOL __stdcall DialogFunc (HWND hDlg, UINT a2, WPARAM a3, LPARAM a4)   {  const  char  *v4;    const  char  *v5;    int  key[11 ];    char  input[8 ];    char  chunk[3 ];    if  ( a2 == 272  )     return  1 ;   if  ( a2 != 273  )     return  0 ;   if  ( a3 == 1001  )   {     memset (input, 0 , 0xFFFF u);     GetDlgItemTextA(hDlg, 1000 , input, 0xFFFF );     if  ( strlen (input) == 8  )     {       key[0 ] = 'Z' ;       key[1 ] = 'J' ;       key[2 ] = 'S' ;       key[3 ] = 'E' ;       key[4 ] = 'C' ;       key[5 ] = 'a' ;       key[6 ] = 'N' ;       key[7 ] = 'H' ;       key[8 ] = '3' ;       key[9 ] = 'n' ;       key[10 ] = 'g' ;       sub_4010F0(key, 0 , 10 );       memset (chunk, 0 , 0xFFFF u);       chunk[0 ] = input[5 ];       chunk[2 ] = input[7 ];       chunk[1 ] = input[6 ];       v4 = sub_401000(chunk, strlen (chunk));       memset (chunk, 0 , 0xFFFF u);       chunk[1 ] = input[3 ];       chunk[0 ] = input[2 ];       chunk[2 ] = input[4 ];       v5 = sub_401000(chunk, strlen (chunk));       if  ( input[0 ] == key[0 ] + 34          && input[1 ] == key[4 ]         && 4  * input[2 ] - 141  == 3  * key[2 ]         && input[3 ] / 4  == 2  * (key[7 ] / 9 )         && !strcmp (v4, "ak1w" )         && !strcmp (v5, "V1Ax" ) )       {         MessageBoxA(hDlg, "U g3t 1T!" , "@_@" , 0 );       }     }     return  0 ;   }   if  ( a3 != 1  && a3 != 2  )     return  0 ;   EndDialog(hDlg, a3);   return  1 ; } 
 
可以看到就是这两个函数,第一个sub_4010F0是对key进行加密,进去跟了一下逻辑好像还有个递归,不管直接动态调试,在OD里面改几个跳转指令,跟一下发现key由ZJSECaNH3ng变为了3CEHJNSZagn 就是个简单的位置变换,
然后就是对sub_401000进行分析了,发现了一个密码表,看样子就是base64了,然后根据后面的判断条件推测一下就能知道input[0]和input[1]了,后面还有个input[3]和input[4]进行验证一下就知道猜想对不对,毕竟我也在字符串列表中找到了变表的base64
接出来是UJWP1jMp,出了
Java 逆向解密 压缩包打开是个class文件,使用Java Decompiler一把梭,发现加密逻辑很简单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 import  java.util.ArrayList;import  java.util.Scanner;public  class  Reverse   {  public  static  void  main (String[] args)   {     Scanner s = new  Scanner(System.in);     System.out.println("Please input the flag );      String str = s.next();     System.out.println(" Your input is );    System.out.println(str);     char [] stringArr = str.toCharArray();     Encrypt(stringArr);   }      public  static  void  Encrypt (char [] arr)   {     ArrayList<Integer> Resultlist = new  ArrayList<>();     for  (int  i = 0 ; i < arr.length; i++) {       int  result = arr[i] + 64  ^ 0x20 ;       Resultlist.add(Integer.valueOf(result));     }      int [] KEY = {          180 , 136 , 137 , 147 , 191 , 137 , 147 , 191 , 148 , 136 ,          133 , 191 , 134 , 140 , 129 , 135 , 191 , 65  };     ArrayList<Integer> KEYList = new  ArrayList<>();     for  (int  j = 0 ; j < KEY.length; j++)       KEYList.add(Integer.valueOf(KEY[j]));      System.out.println("Result:" );     if  (Resultlist.equals(KEYList)) {       System.out.println("Congratulations);      } else {       System.err.println(" Error);    }    } } 
 
直接白给,写脚本出结果
1 2 3 4 5 6 table = [180 , 136 , 137 , 147 , 191 , 137 , 147 , 191 , 148 , 136 ,          133 , 191 , 134 , 140 , 129 , 135 , 191 , 65 ] for  i in  range(len(table)):    table[i] ^= 0x20      table[i] -= 64  print('' .join([chr(x) for  x in  table])) 
 
flag{This_is_the_flag_!}
findit 是个apk,使用dex2jar变成jar之后再使用java decompiler查看逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 package  com.example.findit;import  android.os.Bundle;import  android.support.v7.app.ActionBarActivity;import  android.view.MenuItem;import  android.view.View;import  android.widget.Button;import  android.widget.EditText;import  android.widget.TextView;public  class  MainActivity  extends  ActionBarActivity   {  protected  void  onCreate (Bundle paramBundle)   {     super .onCreate(paramBundle);     setContentView(2130903064 );     Button button = (Button)findViewById(2131034173 );     final  EditText edit = (EditText)findViewById(2131034174 );     final  TextView text = (TextView)findViewById(2131034175 );     button.setOnClickListener(new  View.OnClickListener() {           public  void  onClick (View param1View)   {             char [] arrayOfChar1 = new  char [17 ];             char [] arrayOfChar2 = new  char [38 ];             int  i = 0 ;             while  (true ) {               String str;               if  (i >= 17 ) {                 if  (String.valueOf(arrayOfChar1).equals(edit.getText().toString())) {                   for  (i = 0 ;; i++) {                     if  (i >= 38 ) {                       str = String.valueOf(arrayOfChar2);                       text.setText(str);                       return ;                     }                      if  ((b[i] >= 'A'  && b[i] <= 'Z' ) || (b[i] >= 'a'  && b[i] <= 'z' )) {                       arrayOfChar2[i] = (char )(b[i] + 16 );                       if  ((arrayOfChar2[i] > 'Z'  && arrayOfChar2[i] < 'a' ) || arrayOfChar2[i] >= 'z' )                         arrayOfChar2[i] = (char )(arrayOfChar2[i] - 26 );                      } else  {                       arrayOfChar2[i] = b[i];                     }                    }                    break ;                 }                } else  {                 if  ((a[i] < 'I'  && a[i] >= 'A' ) || (a[i] < 'i'  && a[i] >= 'a' )) {                   str[i] = (char )(a[i] + 18 );                 } else  if  ((a[i] >= 'A'  && a[i] <= 'Z' ) || (a[i] >= 'a'  && a[i] <= 'z' )) {                   str[i] = (char )(a[i] - 8 );                 } else  {                   str[i] = a[i];                 }                  i++;                 continue ;               }                text.setText(");                return;             }            }         });   }      public boolean onOptionsItemSelected(MenuItem paramMenuItem) {     return (paramMenuItem.getItemId() == 2131034176) ? true : super.onOptionsItemSelected(paramMenuItem);   } } 
 
用a/b两个字符串里面的字符变换之后赋值给两个数组,但是,我并不知道这两个数组的内容啊
那就用apktools给解包看看有啥内容,发现MainActivity.smail有俩文件,其中有一个就是数组,复制粘贴下来
1 2 3 4 table1 = [0x54 , 0x68 , 0x69 , 0x73 , 0x49 , 0x73 , 0x54 , 0x68 ,           0x65 , 0x46 , 0x6c , 0x61 , 0x67 , 0x48 , 0x6f , 0x6d , 0x65 , ] table2 = [0x70 ,  0x76 ,  0x6b ,  0x71 ,  0x7b ,  0x6d ,  0x31 ,  0x36 ,  0x34 ,  0x36 ,  0x37 ,  0x35 ,  0x32 ,  0x36 ,  0x32 ,  0x30 ,  0x33 ,  0x33 ,  0x6c ,           0x34 ,  0x6d ,  0x34 ,  0x39 ,  0x6c ,  0x6e ,  0x70 ,  0x37 ,  0x70 ,  0x39 ,  0x6d ,  0x6e ,  0x6b ,  0x32 ,  0x38 ,  0x6b ,  0x37 ,  0x35 ,  0x7d , ] 
 
然后就是去看看两个数组到底是啥内容,直接复制粘贴进idea跑
发现str是LzakAkLzwXdsyZgew直接交,不对,看来还得看看table2的,结果是flag{c164675262033b4c49bdf7f9cda28a75},出了
8086 IDA加载发现是个DOS文件,没有函数,看看汇编
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 seg001:0000 sub_10030       proc near               ; CODE XREF: sub_10030↓j seg001:0000                                         ; start+5↓p seg001:0000                 jmp     short sub_10030 seg001:0000 sub_10030       endp seg001:0000 seg001:0002 ; --------------------------------------------------------------------------- seg001:0002                 mov     cx, 22h ; '"' seg001:0005                 lea     bx, aUDuTZWjQGjzZWz ; "]U[du~|t@{z@wj.}.~q@gjz{z@wzqW~/b;" seg001:0009 seg001:0009 loc_10039:                              ; CODE XREF: seg001:000F↓j seg001:0009                 mov     di, cx seg001:000B                 dec     di seg001:000C                 xor     byte ptr [bx+di], 1Fh seg001:000F                 loop    loc_10039 seg001:0011                 lea     dx, aUDuTZWjQGjzZWz ; "]U[du~|t@{z@wj.}.~q@gjz{z@wzqW~/b;" seg001:0015                 mov     ah, 9 seg001:0017                 int     21h             ; DOS - PRINT STRING seg001:0017                                         ; DS:DX -> string terminated by "$" seg001:0019                 retn seg001:001A                 assume ss:dseg, ds:nothing seg001:001A seg001:001A ; =============== S U B R O U T I N E ======================================= seg001:001A seg001:001A ; Attributes: noreturn seg001:001A seg001:001A                 public start seg001:001A start           proc near seg001:001A                 mov     ax, seg dseg seg001:001D                 mov     ds, ax seg001:001F                 assume ds:dseg seg001:001F                 call    sub_10030 seg001:001F start           endp seg001:001F seg001:0022 ; --------------------------------------------------------------------------- seg001:0022                 mov     ah, 4Ch seg001:0024                 int     21h             ; DOS - 2+ - QUIT WITH EXIT CODE (EXIT) seg001:0024 seg001          ends                    ; AL = exit code seg001:0024 seg001:0024 seg001:0024                 end start 
 
非常简单,对列表里面没一个字符取xor 0x1F就行
写个脚本
1 2 3 4 5 6 7 a = ']U[du~|t@{z@wj.}.~q@gjz{z@wzqW~/b;'  a = list(a) a = [ord(x) for  x in  a] flag = [] for  i in  a:    flag.append(i ^ 0x1f ) print('' .join([chr(x) for  x in  flag])) 
 
出结果BJD{jack_de_hu1b1an_xuede_henHa0}
check_1n 打开一看还真是字符画版的笔记本电脑,有点东西,照样拖进IDA,发现里面一堆函数,main函数的逻辑并不明显,通过找字符找到打印笔记本电脑的函数,然后查看引用
里面的字符串太多了,静态分析感觉都不太好用了,只好上od
md上OD也跟不出个什么鬼,发现一个奇怪的字符串2i9Q8AtFJTfL3ahU2XGuemEqZJ2ensozjg1EjPJwCHy4RY1Nyvn1ZE1bZe
然后大概是有个解密函数,跟进去,发现加密函数异常难看,但是这个应该是解密出来的函数,要是能够跟一下就好了,使用OD在main函数直接跳转,发现在malloc这个函数被卡出来,而且中途还有一堆反调的东西,淦
最后还是通过Shift + F12的方法找到了开机密码HelloWorld
然后有个flag文件,打开之后是虚假的flag, base64解密得Why don't you try the magic brick game
然后试试打砖块
然后输了之后flag自己就出来了,人才.jpg
flag{f5dfd0f5-0343-4642-8f28-9adbb74c4ede}